package com.startx.core.filter.chain;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import org.apache.log4j.Logger;
import org.javatuples.Pair;

import com.startx.core.config.ConfigHolder;
import com.startx.core.filter.StartxFilter;
import com.startx.core.filter.define.Filter;
import com.startx.core.system.config.StartxConfig;
import com.startx.core.system.model.AccessResult;
import com.startx.core.system.model.AccessTarget;
import com.startx.core.system.param.HttpContext;
import com.startx.core.tools.ClassReader;

import io.netty.handler.codec.http.FullHttpRequest;

/**
 * 过滤链工厂
 * @author minghu.zhang
 */
public class FilterFactory {

	//过滤器数组
	private static final List<StartxFilter> filters = new ArrayList<>();
	/**
	 * log 工具
	 */
	private static final Logger Log = Logger.getLogger(FilterFactory.class);
	
	//初始化过滤器
	public static void initFilter() {
		
		StartxConfig config = ConfigHolder.getConfig();
		
		try {
			List<Pair<Integer, Class<?>>> ordered = getOrderedList(config);
			
			for (Pair<Integer, Class<?>> pair : ordered) {
				StartxFilter filter = (StartxFilter) pair.getValue1().newInstance();
				filters.add(filter);
				
				//初始化Log
				Log.info("Add Filter: [order="+pair.getValue0()+"],[class="+pair.getValue1().getName()+"]");
			}
			
		} catch (InstantiationException | IllegalAccessException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获取排序列表
	 * @param config
	 * @return
	 */
	private static List<Pair<Integer, Class<?>>> getOrderedList(StartxConfig config) {
		List<Class<?>> classes = ClassReader.getClasses(config.getPackages());
		
		//待排序列表
		List<Pair<Integer,Class<?>>> ordered = new ArrayList<>();
		for (Class<?> clz : classes) {
			if(clz.isAnnotationPresent(Filter.class)) {
				Filter filtered = clz.getAnnotation(Filter.class);
				int order = filtered.order();
				ordered.add(Pair.with(order, clz));
			}
		}
		
		ordered.sort(new Comparator<Pair<Integer,Class<?>>>() {

			@Override
			public int compare(Pair<Integer, Class<?>> o1, Pair<Integer, Class<?>> o2) {
				
				if(o1.getValue0() > o2.getValue0()) {
					return -1;
				} else if(o1.getValue0() < o2.getValue0()) {
					return 1;
				}
				
				return 0;
			}

		});
		return ordered;
	}
	
	/**
	 * 执行过滤器
	 * @return
	 * @throws Exception 
	 */
	public static boolean doBefore(HttpContext ctx, FullHttpRequest request, AccessTarget target) throws Exception {
		//调用链执行
		for(int i=0;i<filters.size();i++) {
			if(!filters.get(i).doBefore(ctx, request, target)) {
				return false;
			}
		}
		
		return true;
	}
	
	/**
	 * 执行过滤器
	 * @return
	 * @throws Exception 
	 */
	public static boolean doAfter(HttpContext ctx, AccessResult result) throws Exception {
		
		//调用链执行
		for(int i=filters.size()-1;i>=0;i--) {
			if(!filters.get(i).doAfter(ctx, result)) {
				return false;
			}
		}
		
		return true;
	}
	
	//是否已配置过滤器
	public static boolean filterable() {
		return !filters.isEmpty();
	}
	
}
